package net.helix.core.geometry;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL14;
import org.lwjgl.util.glu.MipMap;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;

import net.helix.engine.Engine;
import net.helix.graphics.GraphicsEngine;
import net.helix.graphics.IRenderable;

/**
 * Both LibraryItem_Image and Element_Image share this class.
 * Materials can bind this class.
 * @author Runouw
 *
 */


public class Geometry_Image implements IRenderable {
	public Texture tex = null;
	private boolean fileLoaded = false;
	
	private int glTexId = -1;
	
	private File file;
	
	public Geometry_Image(String addr){
		file = new File(addr);
		
		fileLoaded = false;
	}
	public void loadImageIntoOpenGL(){
		if(fileLoaded == false){
			/*
			String format = "PNG";
			String extension = ImageFilter.getExtension(file.getName());
			if(extension.equalsIgnoreCase("png")){
				format = "PNG";
			}else if(extension.equalsIgnoreCase("gif")){
				format = "GIF";
			}else if(extension.equalsIgnoreCase("jpg") || extension.equalsIgnoreCase("jpe") || extension.equalsIgnoreCase("jpeg")){
				format = "JPG";
			}
			*/
			fileLoaded = true;
			
			try {
				
				InputStream stream = ResourceLoader.getResourceAsStream(file.getAbsolutePath());
				
				tex = TextureLoader.getTexture(Engine.predictfiletype(file.getName()), stream);
				
				stream.close();
			
				glTexId = tex.getTextureID();
			} catch (Exception e) {
				System.out.println("Failed to load: "+file.getPath());
				
				e.printStackTrace();
				
				glTexId = -1;
			}
			
		}
	}
	boolean mipmapped = false;
	private void loadMipMap(){	
		/*
		//tex.bind();
		if(glTexId != -1){
			GL11.glBindTexture(GL11.GL_TEXTURE_2D, glTexId);
			
			
			byte[] texbytes = tex.getTextureData();
			int components = texbytes.length / (((int)tex.getWidth())*((int)tex.getHeight()));
	
			ByteBuffer texdata = BufferUtils.createByteBuffer(texbytes.length);
			texdata.put(texbytes);
			texdata.rewind();
	
			int num = MipMap.gluBuild2DMipmaps(GL11.GL_TEXTURE_2D, components, (int)tex.getWidth(), (int)tex.getHeight(), components==3 ? GL11.GL_RGB : GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, texdata);
			System.out.println("num = "+num);
			
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
			
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
			GL11.glTexParameteri (GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 3);
			
		}
		*/
		mipmapped = true;
	}
	
	@Override
	public void render() {
		if(fileLoaded == false){
			loadImageIntoOpenGL();
		}
		if(tex == null){
			// reddish color box if the image can't be displayed
			GL11.glColor3f(1.0f,0.5f,0.5f);
			
			GL11.glBegin(GL11.GL_QUADS);
			    GL11.glVertex2f(0, 0);
			    GL11.glVertex2f(1, 0);
			    GL11.glVertex2f(1, 1);
			    GL11.glVertex2f(0, 1);
			GL11.glEnd();
		}else{
			GL11.glEnable(GL11.GL_TEXTURE_2D);
			
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
			
			
			GL11.glEnable(GL11.GL_BLEND);
			GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
			
			// TODO: check in properties how it will do alpha blending
			// TODO: one option has to be adding it to a list of objects
			// that gets depth sorted and rendered after everything else
			// TODO: also, this is NOT needed in 2d mode
			GL11.glAlphaFunc(GL11.GL_GREATER, .5f);
			GL11.glEnable(GL11.GL_ALPHA_TEST);
			
			//GL11.glTexEnv(GL11.GL_TEXTURE_ENV, GL11.GL_BLEND, GraphicsHelper.texEvnFloatBuffer);
			// values should be taken from the constraints stack (which still have to be made...)
			float r = 1;
			float g = 1;
			float b = 1;
			float a = 1;
			
			GL11.glColor4f(r,g,b,a); // TODO: image color properties
			
			//tex.bind();
			// manually binding texture because the Texture.bind() messes up
			// when switching gl contexts.
			
			GraphicsEngine.bindTex(glTexId);
			
			float sx = (float)tex.getImageWidth()/(float)tex.getTextureWidth();
			float sy = (float)tex.getImageHeight()/(float)tex.getTextureHeight();
			
			
			GL11.glDisable(GL11.GL_CULL_FACE);
			
			GL11.glBegin(GL11.GL_QUADS);
			    GL11.glTexCoord2f(0  ,0); GL11.glVertex2f(0, tex.getImageHeight());
			    GL11.glTexCoord2f(sx ,0);  GL11.glVertex2f(tex.getImageWidth(), tex.getImageHeight()); 
			    GL11.glTexCoord2f(sx,sy); GL11.glVertex2f(tex.getImageWidth(), 0);
			    GL11.glTexCoord2f(0 ,sy); GL11.glVertex2f(0, 0);
			GL11.glEnd();
			
			GL11.glEnable(GL11.GL_CULL_FACE);
			
			GL11.glDisable(GL11.GL_TEXTURE_2D);   
			GL11.glDisable(GL11.GL_BLEND);
			GL11.glDisable(GL11.GL_ALPHA_TEST);
		}
		
	}
	public float getWidth(){
		if(tex != null){
			return tex.getImageWidth();
		}
		return 1;
	}
	public float getHeight(){
		if(tex != null){
			return tex.getImageHeight();
		}
		return 1;
	}
	public void dispose(){
		// make it remove image...
		if(tex != null){
			// TODO: make it remove the texture from memory...
			// calling this in a thread that wasn't synced with the rendering
			// thread may cause an error
			//tex.release();
			
			GL11.glDeleteTextures(tex.getTextureID());
		}
		tex = null;
		file = null;
		fileLoaded = false;
		glTexId = -1;
	}
	public int getTexId(){
		if(fileLoaded == false){
			loadImageIntoOpenGL();
		}
		if(mipmapped == false){
			loadMipMap();
		}
		if(glTexId == -1){
		}
		
		return glTexId;
	}
	public Texture getTex(){
		if(fileLoaded == false){
			loadImageIntoOpenGL();
		}
		return tex;
	}

}
